home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Demos / ByCompany / TipTop_Software / TipTop / Supplement / src / Z126 / rz.c < prev    next >
Text File  |  1994-05-08  |  26KB  |  1,262 lines

  1. #define VERSION "1.26 08-21-87"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*% cc -M0 -Ox -K -i % -o rz; size rz;
  5. <-xtx-*> cc386 -Ox rz.c -o $B/rz;  size $B/rz
  6.  *
  7.  * rz.c By Chuck Forsberg
  8.  *
  9.  *    cc -O rz.c -o rz        USG (3.0) Unix
  10.  *     cc -O -DV7  rz.c -o rz        Unix V7, BSD 2.8 - 4.3
  11.  *
  12.  *    ln rz rb;  ln rz rx            For either system
  13.  *
  14.  *    ln rz /usr/bin/rzrmail        For remote mail.  Make this the
  15.  *                    login shell. rzrmail then calls
  16.  *                    rmail(1) to deliver mail.
  17.  *
  18.  *
  19.  *  Unix is a trademark of Western Electric Company
  20.  *
  21.  * A program for Unix to receive files and commands from computers running
  22.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  23.  *  rz uses Unix buffered input to reduce wasted CPU time.
  24.  *
  25.  * Iff the program is invoked by rzCOMMAND, output is piped to 
  26.  * "COMMAND filename"
  27.  *
  28.  *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
  29.  *  read(2) the same way as Unix. ONEREAD must be defined to force one
  30.  *  character reads for these systems. Added 7-01-84 CAF
  31.  *
  32.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  33.  *
  34.  *  BIX added 6-30-87 to support BIX(TM) upload protocol used by the
  35.  *  Byte Information Exchange.
  36.  *
  37.  *  NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN]
  38.  *  doesn't work properly (even though it compiles without error!),
  39.  *
  40.  *  HOWMANY may be tuned for best performance
  41.  *
  42.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  43.  */
  44. #define LOGFILE "/tmp/rzlog"
  45.  
  46. #ifdef NeXT
  47. #import <objc/objc.h>
  48. #import "TransferProgressProtocol.h"
  49. id getProgressListener();
  50. static id remote;
  51. #endif
  52.  
  53. #include <stdio.h>
  54. #include <signal.h>
  55. #include <setjmp.h>
  56. #include <ctype.h>
  57. FILE *popen();
  58.  
  59. #define OK 0
  60. #define FALSE 0
  61. #define TRUE 1
  62. #define ERROR (-1)
  63.  
  64. /*
  65.  * Max value for HOWMANY is 255.
  66.  *   A larger value reduces system overhead but may evoke kernel bugs.
  67.  *   133 corresponds to an XMODEM/CRC sector
  68.  */
  69. #ifndef HOWMANY
  70. #define HOWMANY 133
  71. #endif
  72.  
  73. int Zmodem=0;        /* ZMODEM protocol requested */
  74. int Nozmodem = 0;    /* If invoked as "rb" */
  75. unsigned Baudrate;
  76. #include "rbsb.c"    /* most of the system dependent stuff here */
  77.  
  78. char *substr();
  79. FILE *fout;
  80.  
  81. /*
  82.  * Routine to calculate the free bytes on the current file system
  83.  *  ~0 means many free bytes (unknown)
  84.  */
  85. long getfree()
  86. {
  87.     return(~0L);    /* many free bytes ... */
  88. }
  89.  
  90. /* Ward Christensen / CP/M parameters - Don't change these! */
  91. #define ENQ 005
  92. #define CAN ('X'&037)
  93. #define XOFF ('s'&037)
  94. #define XON ('q'&037)
  95. #define SOH 1
  96. #define STX 2
  97. #define EOT 4
  98. #define ACK 6
  99. #define NAK 025
  100. #define CPMEOF 032
  101. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  102. #define TIMEOUT (-2)
  103. #define RCDO (-3)
  104. #define ERRORMAX 5
  105. #define RETRYMAX 5
  106. #define WCEOT (-10)
  107. #define SECSIZ 128    /* cp/m's Magic Number record size */
  108. #define PATHLEN 257    /* ready for 4.2 bsd ? */
  109. #define KSIZE 1024    /* record size with k option */
  110. #define UNIXFILE 0x8000    /* happens to the the S_IFREG file mask bit for stat */
  111.  
  112. int Lastrx;
  113. int Crcflg;
  114. int Firstsec;
  115. int Eofseen;        /* indicates cpm eof (^Z) has been received */
  116. int errors;
  117. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  118. #ifdef ONEREAD
  119. /* Sorry, Regulus and some others don't work right in raw mode! */
  120. int Readnum = 1;    /* Number of bytes to ask for in read() from modem */
  121. #else
  122. int Readnum = HOWMANY;    /* Number of bytes to ask for in read() from modem */
  123. #endif
  124.  
  125. #define DEFBYTL 2000000000L    /* default rx file size */
  126. long Bytesleft;        /* number of bytes of incoming file left */
  127. long Modtime;        /* Unix style mod time for incoming file */
  128. short Filemode;        /* Unix style mode for incoming file */
  129. char Pathname[PATHLEN];
  130. char *Progname;        /* the name by which we were called */
  131.  
  132. int Batch=0;
  133. int Wcsmask=0377;
  134. int Topipe=0;
  135. int MakeLCPathname=TRUE;    /* make received pathname lower case */
  136. int Verbose=0;
  137. int Quiet=0;        /* overrides logic that would otherwise set verbose */
  138. int Nflag = 0;        /* Don't really transfer files */
  139. int Rxbinary=FALSE;    /* receive all files in bin mode */
  140. int Rxascii=FALSE;    /* receive files in ascii (translate) mode */
  141. int Thisbinary;        /* current file is to be received in bin mode */
  142. int Blklen;        /* record length of received packets */
  143. char secbuf[KSIZE+1];
  144. char linbuf[HOWMANY];
  145. int Lleft=0;        /* number of characters in linbuf */
  146. time_t timep[2];
  147. char Lzmanag;        /* Local file management request */
  148. char zconv;        /* ZMODEM file conversion request */
  149. char zmanag;        /* ZMODEM file management request */
  150. char ztrans;        /* ZMODEM file transport request */
  151. int Zctlesc;        /* Encode control characters */
  152. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  153.  
  154. jmp_buf tohere;        /* For the interrupt on RX timeout */
  155.  
  156. #include "zm.c"
  157.  
  158. int tryzhdrtype=ZRINIT;    /* Header type to send corresponding to Last rx close */
  159.  
  160. alrm()
  161. {
  162.     longjmp(tohere, -1);
  163. }
  164.  
  165. /* called by signal interrupt or terminate to clean things up */
  166. bibi(n)
  167. {
  168.     if (Zmodem)
  169.         zmputs(Attn);
  170.     canit(); mode(0);
  171.     fprintf(stderr, "rz: caught signal %d; exiting", n);
  172. #ifdef NeXT
  173.     { char buf[50];
  174.       sprintf(buf,"Caught signal %d; exiting",n);
  175.       [remote transferMessage:buf];
  176.       sleep(1);
  177.       [remote transferEnd];
  178.     }
  179. #endif
  180.     exit(128+n);
  181. }
  182.  
  183. main(argc, argv)
  184. char *argv[];
  185. {
  186.     register char *cp;
  187.     register npats;
  188.     char *virgin, **patts;
  189.     char *getenv();
  190.     int exitcode;
  191.  
  192.     Rxtimeout = 100;
  193.     setbuf(stderr, NULL);
  194.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  195.         Restricted=TRUE;
  196.  
  197.     chkinvok(virgin=argv[0]);    /* if called as [-]rzCOMMAND set flag */
  198.     npats = 0;
  199.     while (--argc) {
  200.         cp = *++argv;
  201.         if (*cp == '-') {
  202.             while( *++cp) {
  203.                 switch(*cp) {
  204.                 case '+':
  205.                     Lzmanag = ZMAPND; break;
  206.                 case '1':
  207.                     iofd = 1; break;
  208.                 case '7':
  209.                     Wcsmask = 0177;
  210.                 case 'a':
  211.                     Rxascii=TRUE;  break;
  212.                 case 'b':
  213.                     Rxbinary=TRUE; break;
  214.                 case 'c':
  215.                     Crcflg=TRUE; break;
  216.                 case 'D':
  217.                     Nflag = TRUE; break;
  218.                 case 'e':
  219.                     Zctlesc = 1; break;
  220.                 case 'p':
  221.                     Lzmanag = ZMPROT;  break;
  222.                 case 'q':
  223.                     Quiet=TRUE; Verbose=0; break;
  224.                 case 't':
  225.                     if (--argc < 1) {
  226.                         usage();
  227.                     }
  228.                     Rxtimeout = atoi(*++argv);
  229.                     if (Rxtimeout<10 || Rxtimeout>1000)
  230.                         usage();
  231.                     break;
  232.                 case 'w':
  233.                     if (--argc < 1) {
  234.                         usage();
  235.                     }
  236.                     Zrwindow = atoi(*++argv);
  237.                     break;
  238.                 case 'u':
  239.                     MakeLCPathname=FALSE; break;
  240.                 case 'v':
  241.                     ++Verbose; break;
  242.                 default:
  243.                     usage();
  244.                 }
  245.             }
  246.         }
  247.         else if ( !npats && argc>0) {
  248.             if (argv[0][0]) {
  249.                 npats=argc;
  250.                 patts=argv;
  251.             }
  252.         }
  253.     }
  254.     if (npats > 1)
  255.         usage();
  256.     if (Verbose) {
  257.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  258.             printf("Can't open log file %s\n",LOGFILE);
  259.             exit(0200);
  260.         }
  261.         setbuf(stderr, NULL);
  262.         fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  263.     }
  264.     if (fromcu() && !Quiet) {
  265.         if (Verbose == 0)
  266.             Verbose = 2;
  267.     }
  268.     mode(1);
  269.     if (signal(SIGINT, bibi) == SIG_IGN) {
  270.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  271.     }
  272.     else {
  273.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  274.     }
  275.     signal(SIGTERM, bibi);
  276. #ifdef NeXT
  277.     remote=getProgressListener();
  278.     [remote transferBegin:(!Batch && npats!=0)?"XMODEM Receive"
  279.                     :(Nozmodem?"YMODEM Receive"
  280.                           :"ZMODEM Receive")];
  281. #endif
  282.     if (wcreceive(npats, patts)==ERROR) {
  283.         exitcode=0200;
  284.         canit();
  285.     }
  286. #ifdef NeXT
  287.     [remote transferEnd];
  288. #endif
  289.     mode(0);
  290.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  291.         canit();
  292.     exit(exitcode);
  293. }
  294.  
  295.  
  296. usage()
  297. {
  298.     fprintf(stderr,"%s %s for %s by Chuck Forsberg\n",
  299.       Progname, VERSION, OS);
  300.     fprintf(stderr,"Usage:    rz [-1abeuv]        (ZMODEM Batch)\n");
  301.     fprintf(stderr,"or    rb [-1abuv]        (YMODEM Batch)\n");
  302.     fprintf(stderr,"or    rx [-1abcv] file    (XMODEM or XMODEM-1k)\n");
  303.     fprintf(stderr,"      -1 For cu(1): Use fd 1 for input\n");
  304.     fprintf(stderr,"      -a ASCII transfer (strip CR)\n");
  305.     fprintf(stderr,"      -b Binary transfer for all files\n");
  306.     fprintf(stderr,"      -c Use 16 bit CRC    (XMODEM)\n");
  307.     fprintf(stderr,"      -e Ignore control characters    (ZMODEM)\n");
  308.     fprintf(stderr,"      -v Verbose more v's give more info\n");
  309.     exit(1);
  310. }
  311. /*
  312.  *  Debugging information output interface routine
  313.  */
  314. /* VARARGS1 */
  315. vfile(f, a, b, c)
  316. register char *f;
  317. {
  318.     if (Verbose > 2) {
  319.         fprintf(stderr, f, a, b, c);
  320.         fprintf(stderr, "\n");
  321.     }
  322. }
  323.  
  324. /*
  325.  * Let's receive something already.
  326.  */
  327.  
  328. char *rbmsg =
  329. "%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n";
  330.  
  331. wcreceive(argc, argp)
  332. char **argp;
  333. {
  334.     register c;
  335.  
  336.     if (Batch || argc==0) {
  337.         Crcflg=(Wcsmask==0377);
  338.         if ( !Quiet)
  339.             fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
  340.         if (c=tryz()) {
  341.             if (c == ZCOMPL)
  342.                 return OK;
  343.             if (c == ERROR)
  344.                 goto fubar;
  345.             c = rzfiles();
  346.             if (c)
  347.                 goto fubar;
  348.         } else {
  349.             for (;;) {
  350.                 if (wcrxpn(secbuf)== ERROR)
  351.                     goto fubar;
  352.                 if (secbuf[0]==0)
  353.                     return OK;
  354.                 if (procheader(secbuf) == ERROR)
  355.                     goto fubar;
  356.                 if (wcrx()==ERROR)
  357.                     goto fubar;
  358.             }
  359.         }
  360.     } else {
  361.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  362.  
  363.         procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
  364. #ifdef NeXT
  365.         [remote transferFileBegin:Pathname];
  366. #endif
  367.         fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
  368.         if ((fout=fopen(Pathname, "w")) == NULL)
  369.             return ERROR;
  370.         if (wcrx()==ERROR)
  371.             goto fubar;
  372.     }
  373.     return OK;
  374. fubar:
  375.     canit();
  376.     if (Topipe && fout) {
  377.         pclose(fout);  return ERROR;
  378.     }
  379.     if (fout)
  380.         fclose(fout);
  381.     if (Restricted) {
  382.         unlink(Pathname);
  383.         fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
  384.     }
  385.     return ERROR;
  386. }
  387.  
  388.  
  389. /*
  390.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  391.  * Length is indeterminate as long as less than Blklen
  392.  * A null string represents no more files (YMODEM)
  393.  */
  394. wcrxpn(rpn)
  395. char *rpn;    /* receive a pathname */
  396. {
  397.     register c;
  398.  
  399. #ifdef NFGVMIN
  400.     readline(1);
  401. #else
  402.     purgeline();
  403. #endif
  404.  
  405. et_tu:
  406.     Firstsec=TRUE;  Eofseen=FALSE;
  407.     sendline(Crcflg?WANTCRC:NAK);
  408.     Lleft=0;    /* Do read next time ... */
  409.     while ((c = wcgetsec(rpn, 100)) != 0) {
  410.         if (c == WCEOT) {
  411.             zperr( "Pathname fetch returned %d", c);
  412.             sendline(ACK);
  413.             Lleft=0;    /* Do read next time ... */
  414.             readline(1);
  415.             goto et_tu;
  416.         }
  417.         return ERROR;
  418.     }
  419.     sendline(ACK);
  420.     return OK;
  421. }
  422.  
  423. /*
  424.  * Adapted from CMODEM13.C, written by
  425.  * Jack M. Wierda and Roderick W. Hart
  426.  */
  427.  
  428. wcrx()
  429. {
  430.     register int sectnum, sectcurr;
  431.     register char sendchar;
  432.     register char *p;
  433.     int cblklen;            /* bytes to dump this block */
  434.  
  435.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  436.     sendchar=Crcflg?WANTCRC:NAK;
  437.  
  438.     for (;;) {
  439.         sendline(sendchar);    /* send it now, we're ready! */
  440.         Lleft=0;    /* Do read next time ... */
  441.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  442.         report(sectcurr);
  443.         if (sectcurr==(sectnum+1 &Wcsmask)) {
  444.             sectnum++;
  445.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  446.             if (putsec(secbuf, cblklen)==ERROR)
  447.                 return ERROR;
  448.             if ((Bytesleft-=cblklen) < 0)
  449.                 Bytesleft = 0;
  450.             sendchar=ACK;
  451.         }
  452.         else if (sectcurr==(sectnum&Wcsmask)) {
  453.             zperr( "Received dup Sector");
  454.             sendchar=ACK;
  455.         }
  456.         else if (sectcurr==WCEOT) {
  457.             if (closeit())
  458.                 return ERROR;
  459.             sendline(ACK);
  460.             Lleft=0;    /* Do read next time ... */
  461.             return OK;
  462.         }
  463.         else if (sectcurr==ERROR)
  464.             return ERROR;
  465.         else {
  466.             zperr( "Sync Error");
  467.             return ERROR;
  468.         }
  469.     }
  470. }
  471.  
  472. /*
  473.  * Wcgetsec fetches a Ward Christensen type sector.
  474.  * Returns sector number encountered or ERROR if valid sector not received,
  475.  * or CAN CAN received
  476.  * or WCEOT if eot sector
  477.  * time is timeout for first char, set to 4 seconds thereafter
  478.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  479.  *    (Caller must do that when he is good and ready to get next sector)
  480.  */
  481.  
  482. wcgetsec(rxbuf, maxtime)
  483. char *rxbuf;
  484. int maxtime;
  485. {
  486.     register checksum, wcj, firstch;
  487.     register unsigned short oldcrc;
  488.     register char *p;
  489.     int sectcurr;
  490.  
  491.     for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
  492.  
  493.         if ((firstch=readline(maxtime))==STX) {
  494.             Blklen=KSIZE; goto get2;
  495.         }
  496.         if (firstch==SOH) {
  497.             Blklen=SECSIZ;
  498. get2:
  499.             sectcurr=readline(1);
  500.             if ((sectcurr+(oldcrc=readline(1)))==Wcsmask) {
  501.                 oldcrc=checksum=0;
  502.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
  503.                     if ((firstch=readline(1)) < 0)
  504.                         goto bilge;
  505.                     oldcrc=updcrc(firstch, oldcrc);
  506.                     checksum += (*p++ = firstch);
  507.                 }
  508.                 if ((firstch=readline(1)) < 0)
  509.                     goto bilge;
  510.                 if (Crcflg) {
  511.                     oldcrc=updcrc(firstch, oldcrc);
  512.                     if ((firstch=readline(1)) < 0)
  513.                         goto bilge;
  514.                     oldcrc=updcrc(firstch, oldcrc);
  515.                     if (oldcrc & 0xFFFF)
  516.                         zperr( "CRC");
  517.                     else {
  518.                         Firstsec=FALSE;
  519.                         return sectcurr;
  520.                     }
  521.                 }
  522.                 else if (((checksum-firstch)&Wcsmask)==0) {
  523.                     Firstsec=FALSE;
  524.                     return sectcurr;
  525.                 }
  526.                 else
  527.                     zperr( "Checksum");
  528.             }
  529.             else
  530.                 zperr("Sector number garbled");
  531.         }
  532.         /* make sure eot really is eot and not just mixmash */
  533. #ifdef NFGVMIN
  534.         else if (firstch==EOT && readline(1)==TIMEOUT)
  535.             return WCEOT;
  536. #else
  537.         else if (firstch==EOT && Lleft==0)
  538.             return WCEOT;
  539. #endif
  540.         else if (firstch==CAN) {
  541.             if (Lastrx==CAN) {
  542.                 zperr( "Sender CANcelled");
  543.                 return ERROR;
  544.             } else {
  545.                 Lastrx=CAN;
  546.                 continue;
  547.             }
  548.         }
  549.         else if (firstch==TIMEOUT) {
  550.             if (Firstsec)
  551.                 goto humbug;
  552. bilge:
  553.             zperr( "TIMEOUT");
  554.         }
  555.         else
  556.             zperr( "Got 0%o sector header", firstch);
  557.  
  558. humbug:
  559.         Lastrx=0;
  560.         while(readline(1)!=TIMEOUT)
  561.             ;
  562.         if (Firstsec) {
  563.             sendline(Crcflg?WANTCRC:NAK);
  564.             Lleft=0;    /* Do read next time ... */
  565.         } else {
  566.             maxtime=40; sendline(NAK);
  567.             Lleft=0;    /* Do read next time ... */
  568.         }
  569.     }
  570.     /* try to stop the bubble machine. */
  571.     canit();
  572.     return ERROR;
  573. }
  574.  
  575. /*
  576.  * This version of readline is reasoably well suited for
  577.  * reading many characters.
  578.  *  (except, currently, for the Regulus version!)
  579.  *
  580.  * timeout is in tenths of seconds
  581.  */
  582. readline(timeout)
  583. int timeout;
  584. {
  585.     register n;
  586.     static char *cdq;    /* pointer for removing chars from linbuf */
  587.  
  588.     if (--Lleft >= 0) {
  589.         if (Verbose > 8) {
  590.             fprintf(stderr, "%02x ", *cdq&0377);
  591.         }
  592.         return (*cdq++ & Wcsmask);
  593.     }
  594.     n = timeout/10;
  595.     if (n < 2)
  596.         n = 3;
  597.     if (Verbose > 5)
  598.         fprintf(stderr, "Calling read: alarm=%d  Readnum=%d ",
  599.           n, Readnum);
  600.     if (setjmp(tohere)) {
  601. #ifdef TIOCFLUSH
  602. /*        ioctl(iofd, TIOCFLUSH, 0); */
  603. #endif
  604.         Lleft = 0;
  605.         if (Verbose>1)
  606.             fprintf(stderr, "Readline:TIMEOUT\n");
  607.         return TIMEOUT;
  608.     }
  609.     signal(SIGALRM, alrm); alarm(n);
  610.     Lleft=read(iofd, cdq=linbuf, Readnum);
  611.     alarm(0);
  612.     if (Verbose > 5) {
  613.         fprintf(stderr, "Read returned %d bytes\n", Lleft);
  614.     }
  615.     if (Lleft < 1)
  616.         return TIMEOUT;
  617.     --Lleft;
  618.     if (Verbose > 8) {
  619.         fprintf(stderr, "%02x ", *cdq&0377);
  620.     }
  621.     return (*cdq++ & Wcsmask);
  622. }
  623.  
  624.  
  625.  
  626. /*
  627.  * Purge the modem input queue of all characters
  628.  */
  629. purgeline()
  630. {
  631.     Lleft = 0;
  632. #ifdef USG
  633.     ioctl(iofd, TCFLSH, 0);
  634. #else
  635.     lseek(iofd, 0L, 2);
  636. #endif
  637. }
  638.  
  639.  
  640. /*
  641.  * Process incoming file information header
  642.  */
  643. procheader(name)
  644. char *name;
  645. {
  646.     register char *openmode, *p, **pp;
  647.  
  648.     /* set default parameters and overrides */
  649.     openmode = "w";
  650.     Thisbinary = (!Rxascii) || Rxbinary;
  651.     if (Lzmanag)
  652.         zmanag = Lzmanag;
  653.  
  654.     /*
  655.      *  Process ZMODEM remote file management requests
  656.      */
  657.     if (!Rxbinary && zconv == ZCNL)    /* Remote ASCII override */
  658.         Thisbinary = 0;
  659.     if (zconv == ZCBIN)    /* Remote Binary override */
  660.         Thisbinary = TRUE;
  661.     else if (zmanag == ZMAPND)
  662.         openmode = "a";
  663.  
  664. #ifndef BIX
  665.     /* ZMPROT check for existing file */
  666.     if (zmanag == ZMPROT && (fout=fopen(name, "r"))) {
  667.         fclose(fout);  return ERROR;
  668.     }
  669. #endif
  670.  
  671.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  672.  
  673.     p = name + 1 + strlen(name);
  674.     if (*p) {    /* file coming from Unix or DOS system */
  675.         sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  676.         if (Filemode & UNIXFILE)
  677.             ++Thisbinary;
  678. #ifdef NeXT
  679.         [remote transferFile:name size:Bytesleft];
  680. #endif
  681.         if (Verbose) {
  682.             fprintf(stderr,  "Incoming: %s %ld %lo %o\n",
  683.               name, Bytesleft, Modtime, Filemode);
  684.         }
  685.     }
  686.  
  687. #ifdef BIX
  688.     if ((fout=fopen("scratchpad", openmode)) == NULL)
  689.         return ERROR;
  690.     return OK;
  691. #else
  692.  
  693.     else {        /* File coming from CP/M system */
  694.         for (p=name; *p; ++p)        /* change / to _ */
  695.             if ( *p == '/')
  696.                 *p = '_';
  697.  
  698.         if ( *--p == '.')        /* zap trailing period */
  699.             *p = 0;
  700.     }
  701.  
  702.     if (!Zmodem && MakeLCPathname && !IsAnyLower(name))
  703.         uncaps(name);
  704.     if (Topipe) {
  705.         sprintf(Pathname, "%s %s", Progname+2, name);
  706.         if (Verbose)
  707.             fprintf(stderr,  "Topipe: %s %s\n",
  708.               Pathname, Thisbinary?"BIN":"ASCII");
  709.         if ((fout=popen(Pathname, "w")) == NULL)
  710.             return ERROR;
  711.     } else {
  712.         strcpy(Pathname, name);
  713.         if (Verbose) {
  714.             fprintf(stderr,  "Receiving %s %s %s\n",
  715.               name, Thisbinary?"BIN":"ASCII", openmode);
  716.         }
  717.         checkpath(name);
  718.         if (Nflag)
  719.             name = "/dev/null";
  720.         if ((fout=fopen(name, openmode)) == NULL)
  721.             return ERROR;
  722.     }
  723.     return OK;
  724. #endif /* BIX */
  725. }
  726.  
  727. /*
  728.  * Putsec writes the n characters of buf to receive file fout.
  729.  *  If not in binary mode, carriage returns, and all characters
  730.  *  starting with CPMEOF are discarded.
  731.  */
  732. putsec(buf, n)
  733. char *buf;
  734. register n;
  735. {
  736.     register char *p;
  737.  
  738.     if (Thisbinary) {
  739.         for (p=buf; --n>=0; )
  740.             putc( *p++, fout);
  741.     }
  742.     else {
  743.         if (Eofseen)
  744.             return OK;
  745.         for (p=buf; --n>=0; ++p ) {
  746.             if ( *p == '\r')
  747.                 continue;
  748.             if (*p == CPMEOF) {
  749.                 Eofseen=TRUE; return OK;
  750.             }
  751.             putc(*p ,fout);
  752.         }
  753.     }
  754.     return OK;
  755. }
  756.  
  757. /*
  758.  *  Send a character to modem.  Small is beautiful.
  759.  */
  760. sendline(c)
  761. {
  762.     char d;
  763.  
  764.     d = c;
  765.     if (Verbose>6)
  766.         fprintf(stderr, "Sendline: %x\n", c);
  767.     write(1, &d, 1);
  768. }
  769.  
  770. xsendline(c)
  771. {
  772.     sendline(c);
  773. }
  774.  
  775. flushmo() {}
  776.  
  777.  
  778.  
  779.  
  780. /* make string s lower case */
  781. uncaps(s)
  782. register char *s;
  783. {
  784.     for ( ; *s; ++s)
  785.         if (isupper(*s))
  786.             *s = tolower(*s);
  787. }
  788. /*
  789.  * IsAnyLower returns TRUE if string s has lower case letters.
  790.  */
  791. IsAnyLower(s)
  792. register char *s;
  793. {
  794.     for ( ; *s; ++s)
  795.         if (islower(*s))
  796.             return TRUE;
  797.     return FALSE;
  798. }
  799.  
  800. /*
  801.  * substr(string, token) searches for token in string s
  802.  * returns pointer to token within string if found, NULL otherwise
  803.  */
  804. char *
  805. substr(s, t)
  806. register char *s,*t;
  807. {
  808.     register char *ss,*tt;
  809.     /* search for first char of token */
  810.     for (ss=s; *s; s++)
  811.         if (*s == *t)
  812.             /* compare token with substring */
  813.             for (ss=s,tt=t; ;) {
  814.                 if (*tt == 0)
  815.                     return s;
  816.                 if (*ss++ != *tt++)
  817.                     break;
  818.             }
  819.     return NULL;
  820. }
  821.  
  822. /*
  823.  * Log an error
  824.  */
  825. /*VARARGS1*/
  826. zperr(s,p,u)
  827. char *s, *p, *u;
  828. {
  829.     if (Verbose <= 0)
  830.         return;
  831.     fprintf(stderr, "Retry %d: ", errors);
  832.     fprintf(stderr, s, p, u);
  833.     fprintf(stderr, "\n");
  834. }
  835.  
  836. /* send cancel string to get the other end to shut up */
  837. canit()
  838. {
  839.     static char canistr[] = {
  840.      24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  841.     };
  842.  
  843.     printf(canistr);
  844.     Lleft=0;    /* Do read next time ... */
  845.     fflush(stdout);
  846. }
  847.  
  848.  
  849. /*
  850.  * Return 1 iff stdout and stderr are different devices
  851.  *  indicating this program operating with a modem on a
  852.  *  different line
  853.  */
  854. fromcu()
  855. {
  856.     struct stat a, b;
  857.     fstat(1, &a); fstat(2, &b);
  858.     return (a.st_rdev != b.st_rdev);
  859. }
  860.  
  861. report(sct)
  862. int sct;
  863. {
  864. #ifdef NeXT
  865.     [remote transferProgress:sct*Blklen];
  866. #endif
  867.     if (Verbose>1)
  868.         fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
  869. }
  870.  
  871. /*
  872.  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
  873.  * If called as [-][dir/../]rzCOMMAND set the pipe flag
  874.  * If called as rb use YMODEM protocol
  875.  */
  876. chkinvok(s)
  877. char *s;
  878. {
  879.     register char *p;
  880.  
  881.     p = s;
  882.     while (*p == '-')
  883.         s = ++p;
  884.     while (*p)
  885.         if (*p++ == '/')
  886.             s = p;
  887.     if (*s == 'v') {
  888.         Verbose=1; ++s;
  889.     }
  890.     Progname = s;
  891.     if (s[0]=='r' && s[1]=='b')
  892.         Nozmodem = TRUE;
  893.     if (s[2] && s[0]=='r' && s[1]=='b')
  894.         Topipe=TRUE;
  895.     if (s[2] && s[0]=='r' && s[1]=='z')
  896.         Topipe=TRUE;
  897. }
  898.  
  899. /*
  900.  * Totalitarian Communist pathname processing
  901.  */
  902. checkpath(name)
  903. char *name;
  904. {
  905.     if (Restricted) {
  906.         if (fopen(name, "r") != NULL) {
  907.             canit();
  908.             fprintf(stderr, "\r\nrz: %s exists\n", name);
  909.             bibi(-1);
  910.         }
  911.         /* restrict pathnames to current tree or uucppublic */
  912.         if ( substr(name, "../")
  913.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  914.             canit();
  915.             fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
  916.             bibi(-1);
  917.         }
  918.     }
  919. }
  920.  
  921. /*
  922.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  923.  *  Handles ZSINIT frame
  924.  *  Return ZFILE if Zmodem filename received, -1 on error,
  925.  *   ZCOMPL if transaction finished,  else 0
  926.  */
  927. tryz()
  928. {
  929.     register c, n;
  930.     register cmdzack1flg;
  931.  
  932.     if (Nozmodem)        /* Check for "rb" program name */
  933.         return 0;
  934.  
  935.  
  936.     for (n=Zmodem?15:5; --n>=0; ) {
  937.         /* Set buffer length (0) and capability flags */
  938.         stohdr(0L);
  939. #ifdef CANBREAK
  940.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  941. #else
  942.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  943. #endif
  944.         if (Zctlesc)
  945.             Txhdr[ZF0] |= TESCCTL;
  946.         zshhdr(tryzhdrtype, Txhdr);
  947.         if (tryzhdrtype == ZSKIP)    /* Don't skip too far */
  948.             tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  949. again:
  950.         switch (zgethdr(Rxhdr, 0)) {
  951.         case ZRQINIT:
  952.             continue;
  953.         case ZEOF:
  954.             continue;
  955.         case TIMEOUT:
  956.             continue;
  957.         case ZFILE:
  958.             zconv = Rxhdr[ZF0];
  959.             zmanag = Rxhdr[ZF1];
  960.             ztrans = Rxhdr[ZF2];
  961.             tryzhdrtype = ZRINIT;
  962.             c = zrdata(secbuf, KSIZE);
  963.             mode(3);
  964.             if (c == GOTCRCW)
  965.                 return ZFILE;
  966.             zshhdr(ZNAK, Txhdr);
  967.             goto again;
  968.         case ZSINIT:
  969.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  970.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  971.                 zshhdr(ZACK, Txhdr);
  972.                 goto again;
  973.             }
  974.             zshhdr(ZNAK, Txhdr);
  975.             goto again;
  976.         case ZFREECNT:
  977.             stohdr(getfree());
  978.             zshhdr(ZACK, Txhdr);
  979.             goto again;
  980.         case ZCOMMAND:
  981.             cmdzack1flg = Rxhdr[ZF0];
  982.             if (zrdata(secbuf, KSIZE) == GOTCRCW) {
  983.                 if (cmdzack1flg & ZCACK1)
  984.                     stohdr(0L);
  985.                 else
  986.                     stohdr((long)sys2(secbuf));
  987.                 purgeline();    /* dump impatient questions */
  988.                 do {
  989.                     zshhdr(ZCOMPL, Txhdr);
  990.                 }
  991.                 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
  992.                 ackbibi();
  993.                 if (cmdzack1flg & ZCACK1)
  994.                     exec2(secbuf);
  995.                 return ZCOMPL;
  996.             }
  997.             zshhdr(ZNAK, Txhdr); goto again;
  998.         case ZCOMPL:
  999.             goto again;
  1000.         default:
  1001.             continue;
  1002.         case ZFIN:
  1003.             ackbibi(); return ZCOMPL;
  1004.         case ZCAN:
  1005.             return ERROR;
  1006.         }
  1007.     }
  1008.     return 0;
  1009. }
  1010.  
  1011. /*
  1012.  * Receive 1 or more files with ZMODEM protocol
  1013.  */
  1014. rzfiles()
  1015. {
  1016.     register c;
  1017.  
  1018.     for (;;) {
  1019.         switch (c = rzfile()) {
  1020.         case ZEOF:
  1021.         case ZSKIP:
  1022.             switch (tryz()) {
  1023.             case ZCOMPL:
  1024.                 return OK;
  1025.             default:
  1026.                 return ERROR;
  1027.             case ZFILE:
  1028.                 break;
  1029.             }
  1030.             continue;
  1031.         default:
  1032.             return c;
  1033.         case ERROR:
  1034.             return ERROR;
  1035.         }
  1036.     }
  1037. }
  1038.  
  1039. /*
  1040.  * Receive a file with ZMODEM protocol
  1041.  *  Assumes file name frame is in secbuf
  1042.  */
  1043. rzfile()
  1044. {
  1045.     register c, n;
  1046.     long rxbytes;
  1047.  
  1048.     Eofseen=FALSE;
  1049.     if (procheader(secbuf) == ERROR) {
  1050.         return (tryzhdrtype = ZSKIP);
  1051.     }
  1052.  
  1053.     n = 20; rxbytes = 0l;
  1054.  
  1055.     for (;;) {
  1056.         stohdr(rxbytes);
  1057.         zshhdr(ZRPOS, Txhdr);
  1058. nxthdr:
  1059.         switch (c = zgethdr(Rxhdr, 0)) {
  1060.         default:
  1061.             vfile("rzfile: zgethdr returned %d", c);
  1062.             return ERROR;
  1063.         case ZNAK:
  1064.         case TIMEOUT:
  1065.             if ( --n < 0) {
  1066.                 vfile("rzfile: zgethdr returned %d", c);
  1067.                 return ERROR;
  1068.             }
  1069.         case ZFILE:
  1070.             zrdata(secbuf, KSIZE);
  1071.             continue;
  1072.         case ZEOF:
  1073.             if (rclhdr(Rxhdr) != rxbytes) {
  1074.                 /*
  1075.                  * Ignore eof if it's at wrong place - force
  1076.                  *  a timeout because the eof might have gone
  1077.                  *  out before we sent our zrpos.
  1078.                  */
  1079.                 errors = 0;  goto nxthdr;
  1080.             }
  1081.             if (closeit()) {
  1082.                 tryzhdrtype = ZFERR;
  1083.                 vfile("rzfile: closeit returned <> 0");
  1084.                 return ERROR;
  1085.             }
  1086.             vfile("rzfile: normal EOF");
  1087.             return c;
  1088.         case ERROR:    /* Too much garbage in header search error */
  1089.             if ( --n < 0) {
  1090.                 vfile("rzfile: zgethdr returned %d", c);
  1091.                 return ERROR;
  1092.             }
  1093.             zmputs(Attn);
  1094.             continue;
  1095.         case ZDATA:
  1096.             if (rclhdr(Rxhdr) != rxbytes) {
  1097.                 if ( --n < 0) {
  1098.                     return ERROR;
  1099.                 }
  1100.                 zmputs(Attn);  continue;
  1101.             }
  1102. moredata:
  1103. #ifdef NeXT
  1104.             [remote transferProgress:rxbytes];
  1105. #endif
  1106.             if (Verbose>1)
  1107.                 fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1108.                   rxbytes, Crc32?" CRC-32":"");
  1109.             switch (c = zrdata(secbuf, KSIZE)) {
  1110.             case ZCAN:
  1111.                 vfile("rzfile: zgethdr returned %d", c);
  1112.                 return ERROR;
  1113.             case ERROR:    /* CRC error */
  1114.                 if ( --n < 0) {
  1115.                     vfile("rzfile: zgethdr returned %d", c);
  1116.                     return ERROR;
  1117.                 }
  1118.                 zmputs(Attn);
  1119.                 continue;
  1120.             case TIMEOUT:
  1121.                 if ( --n < 0) {
  1122.                     vfile("rzfile: zgethdr returned %d", c);
  1123.                     return ERROR;
  1124.                 }
  1125.                 continue;
  1126.             case GOTCRCW:
  1127.                 n = 20;
  1128.                 putsec(secbuf, Rxcount);
  1129.                 rxbytes += Rxcount;
  1130.                 stohdr(rxbytes);
  1131.                 zshhdr(ZACK, Txhdr);
  1132.                 sendline(XON);
  1133.                 goto nxthdr;
  1134.             case GOTCRCQ:
  1135.                 n = 20;
  1136.                 putsec(secbuf, Rxcount);
  1137.                 rxbytes += Rxcount;
  1138.                 stohdr(rxbytes);
  1139.                 zshhdr(ZACK, Txhdr);
  1140.                 goto moredata;
  1141.             case GOTCRCG:
  1142.                 n = 20;
  1143.                 putsec(secbuf, Rxcount);
  1144.                 rxbytes += Rxcount;
  1145.                 goto moredata;
  1146.             case GOTCRCE:
  1147.                 n = 20;
  1148.                 putsec(secbuf, Rxcount);
  1149.                 rxbytes += Rxcount;
  1150.                 goto nxthdr;
  1151.             }
  1152.         }
  1153.     }
  1154. }
  1155.  
  1156. /*
  1157.  * Send a string to the modem, processing for \336 (sleep 1 sec)
  1158.  *   and \335 (break signal)
  1159.  */
  1160. zmputs(s)
  1161. char *s;
  1162. {
  1163.     register c;
  1164.  
  1165.     while (*s) {
  1166.         switch (c = *s++) {
  1167.         case '\336':
  1168.             sleep(1); continue;
  1169.         case '\335':
  1170.             sendbrk(); continue;
  1171.         default:
  1172.             sendline(c);
  1173.         }
  1174.     }
  1175. }
  1176.  
  1177. /*
  1178.  * Close the receive dataset, return OK or ERROR
  1179.  */
  1180. closeit()
  1181. {
  1182.     if (Topipe) {
  1183.         if (pclose(fout)) {
  1184.             return ERROR;
  1185.         }
  1186.         return OK;
  1187.     }
  1188.     if (fclose(fout)==ERROR) {
  1189.         fprintf(stderr, "file close ERROR\n");
  1190.         return ERROR;
  1191.     }
  1192.     if (Modtime) {
  1193.         timep[0] = time(NULL);
  1194.         timep[1] = Modtime;
  1195.         utime(Pathname, timep);
  1196.     }
  1197.     if (Filemode)
  1198.         chmod(Pathname, (07777 & Filemode));
  1199.     return OK;
  1200. }
  1201.  
  1202. /*
  1203.  * Ack a ZFIN packet, let byegones be byegones
  1204.  */
  1205. ackbibi()
  1206. {
  1207.     register n;
  1208.  
  1209.     vfile("ackbibi:");
  1210.     Readnum = 1;
  1211.     stohdr(0L);
  1212.     for (n=3; --n>=0; ) {
  1213.         purgeline();
  1214.         zshhdr(ZFIN, Txhdr);
  1215.         switch (readline(100)) {
  1216.         case 'O':
  1217.             readline(1);    /* Discard 2nd 'O' */
  1218.             vfile("ackbibi complete");
  1219.             return;
  1220.         case RCDO:
  1221.             return;
  1222.         case TIMEOUT:
  1223.         default:
  1224.             break;
  1225.         }
  1226.     }
  1227. }
  1228.  
  1229.  
  1230.  
  1231. /*
  1232.  * Local console output simulation
  1233.  */
  1234. bttyout(c)
  1235. {
  1236.     if (Verbose || fromcu())
  1237.         putc(c, stderr);
  1238. }
  1239.  
  1240. /*
  1241.  * Strip leading ! if present, do shell escape. 
  1242.  */
  1243. sys2(s)
  1244. register char *s;
  1245. {
  1246.     if (*s == '!')
  1247.         ++s;
  1248.     return system(s);
  1249. }
  1250. /*
  1251.  * Strip leading ! if present, do exec.
  1252.  */
  1253. exec2(s)
  1254. register char *s;
  1255. {
  1256.     if (*s == '!')
  1257.         ++s;
  1258.     mode(0);
  1259.     execl("/bin/sh", "sh", "-c", s);
  1260. }
  1261. /* End of rz.c */
  1262.